import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  OnDestroy,
  OnInit,
  TemplateRef,
  ViewChild,
} from '@angular/core';
import {
  AdvancedFilterComponent,
  DatatableComponent,
  FieldItem,
  FilterItem,
  MessageboxService,
  PaginatorComponent,
  TagItem,
} from '@iux/live';
import { Subject, Observable } from 'rxjs';
import { cloneDeep, filter, uniqueId } from 'lodash';

@Component({
  selector: 'app-advanced-filter-table',
  templateUrl: './advanced-filter-table.component.html',
  styles: [
    `
      ::ng-deep .age-panel .lv-popover-inner {
        padding: 0;
      }
      .age-filter-select {
        min-width: 2rem;
      }
      lv-paginator {
        margin-top: 16px;
      }
      .name-filter-operation {
        display: flex;
        justify-content: flex-end;
        margin: 5px 0 0 0;

        .lv-button:last-child {
          margin-left: 16px;
        }
      }
    `,
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AdvancedFilterTableComponent implements OnInit, OnDestroy {
  data: any[];
  listenSearch = true;
  filtersMap: { [key: string]: any } = {};
  cacheFiltersMap: { [key: string]: any } = {};
  filterState: FilterItem[] = [];
  rangeDate: [Date, Date] = null;
  selectRangeDate = this.rangeDate; // 与综合筛选器的联动，表格中过滤的日期组件样式和综合筛选器的日期组件保持一致，表格中日期图标的高亮和日期组件的回显所需。
  nameFilterValue: string;
  ageFilterValue: string;
  fields: FieldItem[] = [];
  rangeDatePanelVisible = false;
  nameSearchPanelVisible = false;
  agePanelVisible = false;
  destroy$ = new Subject<void>();
  advancedSelectedFilter = [];

  @ViewChild(DatatableComponent, { static: false }) lvTable: DatatableComponent;
  @ViewChild(PaginatorComponent, { static: false }) lvPage: PaginatorComponent;
  @ViewChild('nameFilterTpl', { static: true }) nameFilterTpl: TemplateRef<any>;
  @ViewChild('ageFilterTpl', { static: true }) ageFilterTpl: TemplateRef<any>;
  @ViewChild(AdvancedFilterComponent, { static: false }) lvAdvancedFilter: AdvancedFilterComponent;
  ageFilters = [
    {
      key: -1,
      label: '全部',
      value: 'all',
    },
    {
      key: 0,
      label: '0',
      value: '0',
    },
    {
      key: 1,
      label: '10',
      value: '10',
    },
    {
      key: 2,
      label: '15',
      value: '15',
    },
    {
      key: 3,
      label: '20',
      value: '20',
    },
    {
      key: 4,
      label: '25',
      value: '25',
    },
    {
      key: 5,
      label: '30',
      value: '30',
    },
    {
      key: 6,
      label: '35',
      value: '35',
    },
  ];
  private allField = ['name', 'age', 'date'];

  constructor(private messageBox: MessageboxService, private cdr: ChangeDetectorRef) {}

  ngOnInit(): void {
    this.fields = this.setFields();
    this.initData();
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }

  setFields(): FieldItem[] {
    return [
      {
        label: 'Name',
        field: 'name',
        type: 'customize',
        mode: 'startsWith',
        option: {
          render: this.nameFilterTpl,
        },
      },
      {
        label: 'Age',
        field: 'age',
        type: 'single',
        option: {
          items: this.ageFilters,
          lvShowCheckAll: true,
        },
      },
      {
        label: 'Date',
        field: 'date',
        type: 'dateRangePicker',
        mode: 'rangeIn',
      },
    ];
  }

  initData(): void {
    this.data = Array.from({ length: 30 }).map((item, key) => this.initUser(key));
    this.setFilters();
  }

  initUser(key: number) {
    const temp = {
      id: uniqueId('uid'),
      name: `user${key}`,
      age: 10 + key,
      expand: false,
      random: parseInt(`${Math.random() * 100}`, 10),
      date: new Date(new Date().getTime() - 60 * 60 * 24 * 1000 * key),
    };
    return temp;
  }

  customFilterName(data, option) {
    return filter(data, item => item[option.key].includes(option.value));
  }

  stateChange(source: any) {
    console.log('state update:', source);
  }

  trackBy = (_, item: TagItem): string => item.label.key;

  beforeRemove = () =>
    new Observable(observer => {
      this.messageBox.confirm({
        lvHeader: 'Delete',
        lvContent: 'Are you sure you want to delete?',
        lvAfterClose: () => {
          observer.next(false);
          observer.complete();
        },
        lvOk: () => {
          observer.next(true);
        },
      });
    });

  toggleListenSearch(listenStatus: boolean, value?: string) {
    this.listenSearch = listenStatus;
    if (!listenStatus) {
      return this.lvTable.removeFilter('name');
    }
  }

  setFilters(): void {
    this.filtersMap.age = cloneDeep(this.ageFilters);
    this.filtersMap.name = '';
    this.cacheFiltersMap = cloneDeep(this.filtersMap);
  }

  filterChange(options: any): void {
    const { key, value } = options;
    if (key === 'age') {
      this.fields.find(item => item.field === key).defaultValue = value[0];
      this.fields = [...this.fields];
      if (value?.includes('all')) {
        this.removeFilterState(key);
        return;
      }
    }
    this.lvTable.filter(options);
    this.lvPage.jumpToFisrtPage();
    this.cdr.markForCheck();
  }

  removeFilterState(key: string): void {
    this.lvTable.removeFilter(key);
    setTimeout(() => this.lvAdvancedFilter.onRemoveTag({ label: '', field: key }), 200);
  }

  clearFilterState(): void {
    this.lvTable.removeFilter();
    this.lvPage.jumpToFisrtPage();
    this.setFilters();
  }

  changeSort(options: any): void {
    this.lvTable.sort(options);
    this.lvPage.jumpToFisrtPage();
  }

  cancelDate(): void {
    this.rangeDatePanelVisible = false;
  }

  selectDate(): void {
    this.selectRangeDate = this.rangeDate;
    if (!this.selectRangeDate || (this.selectRangeDate[0] === null && this.selectRangeDate[1] === null)) {
      this.rangeDatePanelVisible = false;
      this.fields.find((item: FieldItem) => item.type === 'dateRangePicker').defaultValue = null;
      this.removeFilterState('date');
    } else {
      this.lvTable.filter({
        key: 'date',
        value: this.selectRangeDate,
        filterMode: 'timeIn',
      });
      this.rangeDatePanelVisible = false;
      this.fields.find((item: FieldItem) => item.type === 'dateRangePicker').defaultValue = this.selectRangeDate;
    }
    this.fields = [...this.fields];
  }

  getSelectedrangeDate(): boolean {
    // rangeDate 清空时为[null, null]
    if (this.selectRangeDate?.length) {
      return JSON.stringify(this.selectRangeDate) !== JSON.stringify([null, null]) || this.rangeDatePanelVisible;
    }
    return this.rangeDatePanelVisible;
  }

  openRangeDatePanel(event): void {
    event.stopPropagation();
    this.rangeDate = this.selectRangeDate;
    this.rangeDatePanelVisible = !this.rangeDatePanelVisible;
  }

  openNameSearchPanel(): void {
    this.nameSearchPanelVisible = !this.nameSearchPanelVisible;
  }
  openAgePanel(): void {
    this.agePanelVisible = !this.agePanelVisible;
  }

  filterByName(value: string): void {
    if (!value) {
      return;
    }
    this.nameSearchPanelVisible = false;
    this.lvTable.filter({ key: 'name', value, customFilter: this.customFilterName });
    this.fields.find(item => item.field === 'name').defaultValue = value;
    this.fields = [...this.fields];
  }

  onChange({ selectedFilters, currentFilter }): void {
    // 清除所有筛选条件
    if (!selectedFilters?.length || !currentFilter) {
      this.initTableFilter();
    }
    if (selectedFilters?.length) {
      selectedFilters.forEach(item => this.tableFilter(item));
    }
    this.advancedSelectedFilter = selectedFilters;
  }

  tableFilter(filter): void {
    if (filter.type === 'dateRangePicker') {
      // Date
      this.selectRangeDate = filter.filteredValue;
      this.rangeDate = filter.filteredValue;
      this.lvTable.filter({
        key: filter.field,
        value: this.selectRangeDate,
        filterMode: 'timeIn',
      });
    } else if (filter.field === 'name') {
      this.nameFilterValue =  filter.filteredValue;
      this.lvTable.filter({
        key: 'name',
        value: filter.filteredValue,
        customFilter: this.customFilterName,
      });
    } else if (filter.field === 'age') {
      const selectValue: string = filter.filteredValue?.value;
      if (selectValue === 'all') {
        this.removeFilterState('age');
      } else {
        this.lvTable.filter({
          key: 'age',
          value: [selectValue],
          filterMode: 'in',
        });
      }
      this.ageFilterValue = selectValue;
      this.filtersMap.age.forEach(item => {
        item.selected = false;
        if (item.value === selectValue) {
          item.selected = true;
        }
      });
    }
  }

  toggleFilter(selectItem: any): void {
    // 再次选择去除选中的项
    if (this.ageFilterValue === selectItem.value) {
      this.ageFilterValue = null;
      this.removeFilterState('age');
    } else {
      this.ageFilterValue = selectItem.value;
      if (this.ageFilterValue === 'all') {
        this.lvTable.removeFilter('age');
      } else {
        this.lvTable.filter({
          key: 'age',
          value: [this.ageFilterValue],
          filterMode: 'in',
        });
      }
      this.filtersMap.age.forEach(item => {
        item.selected = false;
        if (item.value === selectItem.value) {
          item.selected = true;
        }
      });
    }
    this.agePanelVisible = false;
    const selectValue = this.fields.find(item => item.field === 'age');
    selectValue.defaultValue = this.ageFilterValue;
    this.fields = [...this.fields];
  }

  initTableFilter(): void {
    this.nameFilterValue = '';
    this.ageFilterValue = null;
    this.rangeDate = null;
    this.selectRangeDate = null;
    this.nameSearchPanelVisible = false;
    this.rangeDatePanelVisible = false;
    this.agePanelVisible = false;
    this.allField.forEach(item => {
      this.removeFilterState(item);
    });
    this.fields.forEach(item => (item.defaultValue = null));
    this.fields = [...this.fields];
  }
}
